package core.iterfaces;

import exception.NotSupportException;

import java.util.Optional;

/**
 * 向量接口，表示向量的各种操作
 */
public interface Vec {
    /**
     * 返回一个全0的向量，与当前向量长度相等
     * @return 结果向量
     */
    Vec zero();

    /**
     * 返回一个全0的向量，长度为指定长度，但类型与当前向量相同
     * @param len 结果向量长度
     * @return 结果向量
     */
    Vec zero(int len);
    /**
     * 获取向量的元素
     * @param i 表示第i个元素
     * @return 范围第i个元素的值
     */
    double get(int i);

    /**
     * 设置向量的值
     * @param i   向量索引
     * @param value   值
     */
    void set(int i,double value);

    /**
     * 获取当前向量的长度
     * @return 向量长度
     */
    int len();

    /**
     * 拷贝当前的向量到另一个向量
     * @return  copy后的新向量
     */
    default Vec copy() {
        Vec result = zero();
        for (int i=0;i<len();i++){
            result.set(i,get(i));
        }
        return result;
    }


    /**
     * copy向量的一部分从 from 到 to的位置,包含from,不包含to
     * @param from  起始位置
     * @param to  结束位置
     * @return copy后的新向量
     */
     default Vec sub(int from,int to) {
         Vec result = zero(to-from);
         for(int i=0;i<result.len();i++){
             result.set(i,get(i+from));
         }
         return result;
     }

    /**
     * 计算向量范数值
     * @param p 表示第几范数，1表示1范数 2表示2范数 0表述无穷范数
     * @return 返回向量范数
     */
    default double normal(int p) throws NotSupportException{
        if(p<0){
            throw new NotSupportException("The p must be integer and  greater than zero!");
        }
        double result = 0.0;
        if(p>0) {
            for (int i = 0; i < len(); i++) {
                if (p == 1) {
                    result += Math.abs(get(i));
                } else {
                    result += Math.pow(get(i), p);
                }
            }
            result = Math.pow(result, 1.0 / ((double) p));
        }
        else{
            result = get(0);
            for(int i=0;i<len();i++){
                if(result<get(i)){
                    result = get(i);
                }
            }
        }
        return result;
    }


    /**
     * 向量内积
     * @param other 另一个相乘的向量
     * @return 内积
     */
    default double innerProduct(Vec other) throws NotSupportException{
        if(!Optional.ofNullable(other).isPresent()||other.len()!=len()){
            throw new NotSupportException("Other must not be null and the length of other must be equals length of this!");
        }
        double result = 0.0;
        for(int i=0;i<other.len();i++){
            result +=get(i)*other.get(i);
        }
        return result;
    }


    /**
     * 另一个向量
     * @param other 另一个向量
     * @return 结果矩阵
     */
    Matrix outProduct(Vec other) throws NotSupportException;

    /**
     * 向量与标量的乘积，返回一个向量
     * @param a  乘数标量
     * @param isCovered 是否覆盖原向量，true表示覆盖，false表示不覆盖
     * @return 返回的向量
     */
    default Vec muti(double a,boolean isCovered) {
        if(isCovered){
            for (int i=0;i<len();i++){
                set(i,get(i)*a);
            }
            return this;
        }
        else{
            Vec result = zero();
            result.muti(a,true);
            return result;
        }
    }

    /**
     * 判断两个Vec是否相等
     * @param other 比较的Vec
     * @return 返回是否相等
     */
    default boolean isEqual(Vec other) throws NotSupportException{
        if (!Optional.ofNullable(other).isPresent()||other.len()!=len()){
            throw new NotSupportException("Other must not be null and the length of this must be equals to length of this!");
        }
        for (int i=0;i<len();i++){
            if(get(i)!=other.get(i)){
                return false;
            }
        }
        return true;
    }

    /**
     * 判断两个Vec是否正交
     * @param other 另一个向量
     * @return 返回是否正交
     */
    default boolean isOrthogonality(Vec other) throws NotSupportException{
        if(!Optional.ofNullable(other).isPresent()||other.len()!=len()){
            throw new NotSupportException("Other must not be null and the len of other must be equal to this!");
        }
        return innerProduct(other)==0.0;
    }

    /**
     * 行向量与矩阵相乘，返回一个行向量
     * @param matrix 相乘的矩阵
     * @return 行向量
     */
    default Vec muti(Matrix matrix) throws NotSupportException{
        if(!Optional.ofNullable(matrix).isPresent()||matrix.getRowLen()!=len()){
            throw new NotSupportException("Matrix must not be null and the row length of matrix must be equals to the length of this!");
        }
        Vec result = zero(matrix.getColLen());
        for(int j=0;j<matrix.getColLen();j++){
            result.set(j,innerProduct(matrix.getCol(j)));
        }
        return result;
    }

    /**
     * 向量相加，返回结果向量
     * @param other 相加的向量
     * @param isCovered 表示是否覆盖原向量，true表示覆盖，false表示返回新向量
     * @return 结果向量
     */
    default Vec add(Vec other,boolean isCovered) throws NotSupportException {
        if (!Optional.ofNullable(other).isPresent()||other.len()!=len()) {
            throw new NotSupportException("Other Matrix must not be null and the length of other must be equals length of this!");
        }
        if(isCovered){
            for (int i=0;i<len();i++) {
                set(i,get(i)+other.get(i));
            }
            return this;
        }
        else{
            Vec result = copy();
            result.add(other,true);
            return result;
        }
    }
}
